package com.cnc.common.web.filter;

import com.cnc.common.lang.exception.ApiRuntimeException;
import com.cnc.common.lang.exception.BizException;
import com.cnc.common.lang.utils.BeanUtils;
import com.cnc.common.lang.utils.JSONUtils;
import com.cnc.common.lang.utils.validate.ValidateUtils;
import com.cnc.common.web.upload.FileUpload;
import com.cnc.common.web.upload.UploadFileFilter;
import com.cnc.common.web.upload.info.ListMultiFileInfo;
import com.cnc.common.web.util.AOPUtils;
import com.cnc.common.web.util.ValidationUtils;
import com.cnc.common.web.util.VerifyFileType;
import com.cnc.common.web.vo.FileVo;
import com.cnc.common.web.vo.ImageListVo;
import com.cnc.common.web.vo.ImageVo;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.jboss.resteasy.annotations.Form;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;

/**
 * 作者： cnc
 * 创建时间：2017-09-27.
 * 版本：1.0
 */
@Component
@Aspect
@Order(1)
public class ApiFileAspect {

    @Autowired
    private FileUpload<ListMultiFileInfo> fileUpload;

    public Object apiAspect(ProceedingJoinPoint pjp) throws Throwable {
        Method method = AOPUtils.getMethod(pjp);        //获取切面中的方法
        if(isFileRequest(method)){
            Object[] parameterValues = pjp.getArgs();   //参数的值
            //获取方法的参数
            Parameter[] parameters = method.getParameters();
            //获取request对象的下标
            int requestIndex = AOPUtils.getValueByType(HttpServletRequest.class, parameters);
            if(requestIndex != -1){
                HttpServletRequest request = (HttpServletRequest) parameterValues[requestIndex];
                if(fileUpload == null){
                    throw new ApiRuntimeException("没有配置fileUpload,无法使用该功能进行文件上传！");
                }
                int len = parameterValues.length-1;
                //获取表单参数Vo,将信息注入进去，注意，这里的表单VO对象只能放到参数列表的最后，并且有@Form注解
                Form form = parameters[len].getAnnotation(Form.class);
                if(len>0 && form !=null){
                    Class formClass = parameterValues[len].getClass();
                    //如果是单个上传的图片，当发现上传的不是真实图片，报错
                    if(ImageVo.class.getName().equals(formClass.getName())){
                        fileUpload.setFilter(new UploadFileFilter() {
                            @Override
                            public boolean accept(FileItem item) {
                                try {
                                    if(!VerifyFileType.isImage(item.getInputStream())){
                                        String message = "您上传的不是图片";
                                        String fileType = VerifyFileType.getFileType(item.getInputStream());
                                        if (fileType != null) {
                                            message = "您上传的不是图片，其文件的实际类型为" + fileType;
                                        }
                                        throw new BizException(message);
                                    }
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    return false;
                                }
                                return true;
                            }
                        });
                    }
                    if(ImageListVo.class.getName().equals(formClass.getName())){
                        fileUpload.setFilter(new UploadFileFilter() {
                            @Override
                            public boolean accept(FileItem item) {
                                try {
                                    if (!VerifyFileType.isImage(item.getInputStream())){
                                        return false;
                                    }
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    return false;
                                }
                                return true;
                            }
                        });
                    }

                    try {
                        ListMultiFileInfo fileUploadInfo = fileUpload.parseUploadFile(request);
                        Map<String,Object> params = fileUploadInfo.getParameters();

                        Object vo = JSONUtils.toObject(params, formClass);
                        Map map = BeanUtils.toMap(vo);
                        if(fileUploadInfo.getFiles()!=null && fileUploadInfo.getFiles().size()>0){
                            map.put(FileVo.FileItemsStr,fileUploadInfo.getFiles());
                            map.put(FileVo.FileItemStr,fileUploadInfo.getFiles().get(0));
                        }
                        parameterValues[len] = BeanUtils.toBean(parameterValues[len].getClass(),map);
                        //验证
                        ValidationUtils.validate(parameterValues[len]);
                    } catch (FileUploadException e) {
                        e.printStackTrace();
                    }
                }
                return pjp.proceed(parameterValues);
            }
        }
        return pjp.proceed();
    }

    /**
     * 判断是不是文件头请求
     * @param method
     * @return
     */
    private boolean isFileRequest(Method method) {
        Consumes consumes = method.getAnnotation(Consumes.class);//consumes： 指定处理请求的提交内容类型（Content-Type），例如application/json, text/html;produces: 指定返回的内容类型，仅当request请求头中的(Accept)类型中包含该指定类型才返回；
        if(consumes!= null){
            String[] values = consumes.value();
            for (int i = 0; i <values.length ; i++) {
                if(values[i].contains(MediaType.MULTIPART_FORM_DATA)){  //判断请求提交内容类型 如果 是 "multipart/form-data" 则返回true
                    return true;
                }
            }
        }
        return false;
    }
}
